home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Tricks of the Mac Game Programming Gurus
/
TricksOfTheMacGameProgrammingGurus.iso
/
More Source
/
Pascal
/
NewWatch
/
NewWatch.p
< prev
next >
Wrap
Text File
|
1995-04-25
|
16KB
|
639 lines
{This program was written by Eric Kilk in 1985, as a Desk Accessory. It was revived in 1995 by Ken Long,}
{who turned it into an application. After he posted it to alt.sources.mac, I (Ingemar R), modified it to give it}
{some functionality I found lacking. New features:}
{}
{• Updates automatically}
{• Resizeable}
{• More hour marks}
{• Optional digits (3, 6, 9 and 12), roman or arabic}
{• Black or white}
{}
{Do you feel like working some more on it? Colorize? Seconds? Circular WDEF? Put it in the menu bar?}
{More options?}
{}
{- Fixes 21 of april:}
{• Checked the "can background" flag so it updates when in the background}
{• Modified the hands so they draw correctly}
{}
{- 25 of April:}
{Ken Long released his C version of this code, which added a second hand (Second}
{hand code? I guess so.) and I really can't let the Pascal version fall behind… so I}
{added seconds here too - but made it optional. So:}
{• A hand for seconds.}
{• Incorporated Ken's BNDL and icons.}
{• Thicker hands as an option.}
{• Added a circular WDEF. (Source to that is not included at this time.)}
{• Checked the "Get front clicks" flag as suggested by someone in a.s.m.}
{• Added project and IFC's for MetroWerks Pascal.}
program NewWatch;
{$IFC UNDEFINED THINK_PASCAL}
uses
Types, QuickDraw, Events, Menus, Dialogs, Fonts, Resources, Devices;
{$ENDC}
const
appleID = 1;
fileID = 2;
editID = 3;
optionsID = 4;
helpItem = 1;
defaultItem = 2;
quitItem = 4;
kTwoPi = 6.2831;
var
appleMenu, fileMenu, editMenu, optionsMenu: MenuHandle;
clockWindow, whatWindow: WindowPtr;
dragRect: Rect;
type
settingsType = packed record
display: Integer;
black: Boolean;
seconds: Boolean;
fancy: Boolean;
end;
var
settings: SettingsType;
gDone, gHasWNE, gColorQDFlag, g32bQDFlag: Boolean;
gPrevDateTime: DateTimeRec;
type
WindowTemplate = record
boundsRect: Rect;
procID: Integer;
visible: Boolean;
filler1: Boolean;
goAwayFlag: Boolean;
filler2: Boolean;
refCon: LongInt;
title: Str255;
end;
WindowTPtr = ^WindowTemplate;
WindowTHnd = ^WindowTPtr;
var
wt: WindowTHnd;
procedure EK;
begin
Move(-3, 0);
Line(0, 4);
Move(1, -4);
Line(1, 0);
Move(-1, 2);
Line(0, 0);
Move(0, 2);
Line(1, 0);
Move(2, -4);
Line(0, 4);
Move(1, -2);
Line(2, -2);
Move(-1, 3);
Line(1, 1);
end; {EK}
procedure DrawHands (dateTime: DateTimeRec);
var
mx, my, hx, hy, sx, sy: Integer; {• hand end-points */}
m1x, m1y, m2x, m2y: Integer;
h1x, h1y, h2x, h2y: Integer;
r: Rect;
minUnit, min, hr, sec, secUnit: Double; {• time */}
cxSize, cySize: Integer;
hourRgn, minuteRgn, secRgn: RgnHandle;
const
kSecondLength = 0.8;
kMinuteLength = 0.75;
kHourLength = 0.5;
kMinuteSpecial = 0.55;
kHourSpecial = 0.4;
kMinuteWidth = 0.07;
kHourWidth = 0.10;
function Sgn (arg: Integer): Integer;
begin
if arg > 0 then
Sgn := 1
else if arg < 0 then
Sgn := -1
else
Sgn := 0;
end; {Sgn}
begin
SetPort(clockWindow);
cxSize := (clockWindow^.portRect.right - clockWindow^.portRect.left) div 2;
cySize := (clockWindow^.portRect.bottom - clockWindow^.portRect.top) div 2;
SetOrigin(-cxSize, -cySize); {• make 0,0 in center */}
minUnit := dateTime.minute / 60.0;
min := minUnit * kTwoPi; {• 2*pi */}
hr := (dateTime.hour + minUnit) / 12.0 * kTwoPi;
mx := Trunc(kMinuteLength * cxSize * sin(min));
my := Trunc(-kMinuteLength * cySize * cos(min));
if settings.fancy then {Fancy hands}
begin
m1x := Trunc(kMinuteSpecial * cxSize * sin(min + kMinuteWidth));
m1y := Trunc(-kMinuteSpecial * cySize * cos(min + kMinuteWidth));
m2x := Trunc(kMinuteSpecial * cxSize * sin(min - kMinuteWidth));
m2y := Trunc(-kMinuteSpecial * cySize * cos(min - kMinuteWidth));
end;
hx := Trunc(kHourLength * cxSize * sin(hr));
hy := Trunc(-kHourLength * cySize * cos(hr));
if settings.fancy then {Fancy hands}
begin
h1x := Trunc(kHourSpecial * cxSize * sin(hr + kHourWidth));
h1y := Trunc(-kHourSpecial * cySize * cos(hr + kHourWidth));
h2x := Trunc(kHourSpecial * cxSize * sin(hr - kHourWidth));
h2y := Trunc(-kHourSpecial * cySize * cos(hr - kHourWidth));
end;
{Additions for seconds:}
if settings.seconds then
begin
secUnit := dateTime.second / 60.0;
sec := secUnit * kTwoPi;
sx := Trunc(kSecondLength * cxSize * sin(sec));
sy := Trunc(-kSecondLength * cySize * cos(sec));
end;
hourRgn := NewRgn;
minuteRgn := NewRgn;
secRgn := NewRgn;
if settings.seconds then
begin
OpenRgn;
MoveTo(0, 0); {• create the seconds hand region}
LineTo(sx, sy);
if abs(sx) > abs(sy) then
Line(0, Sgn(sx))
else
Line(-Sgn(sy), 0);
Line(-sx, -sy);
LineTo(0, 0);
CloseRgn(secRgn);
end;
OpenRgn;
MoveTo(0, 0); {• create the minute hand region}
if settings.fancy then
LineTo(m2x, m2y);
LineTo(mx, my);
if abs(mx) > abs(my) then
Line(0, Sgn(mx))
else
Line(-Sgn(my), 0);
if settings.fancy then
begin
Line(m1x - mx, m1y - my);
Line(-m1x, -m1y);
end
else
Line(-mx, -my);
LineTo(0, 0);
CloseRgn(minuteRgn);
OpenRgn;
MoveTo(0, 0); {• create the hour hand region}
if settings.fancy then
LineTo(h2x, h2y);
LineTo(hx, hy);
if abs(hx) > abs(hy) then
Line(0, Sgn(hx))
else
Line(-Sgn(hy), 0);
if settings.fancy then
begin
Line(h1x - hx, h1y - hy);
Line(-h1x, -h1y);
end
else
Line(-hx, -hy);
LineTo(0, 0);
CloseRgn(hourRgn);
UnionRgn(hourRgn, minuteRgn, minuteRgn);
if settings.seconds then
UnionRgn(secRgn, minuteRgn, minuteRgn);
PaintRgn(minuteRgn); {• draw the hands.}
DisposeRgn(minuteRgn);
DisposeRgn(hourRgn);
DisposeRgn(secRgn);
{MoveTo(0, 0); {• erase the center dot.}
{PenPat(white);}
{LineTo(0, 0);}
{PenPat(black);}
end; {DrawHands}
procedure ShowClock;
{• draw the entire clock face */}
var
dateTime: DateTimeRec; {• date gets read into here */}
cxSize, cySize: Integer;
fInfo: FontInfo;
theTextSize: Integer;
begin
SetPort(clockWindow);
PenNormal;
if settings.black then
PaintRect(clockWindow^.portRect)
else
EraseRect(clockWindow^.portRect);
cxSize := (clockWindow^.portRect.right - clockWindow^.portRect.left) div 2;
cySize := (clockWindow^.portRect.bottom - clockWindow^.portRect.top) div 2;
GetTime(dateTime);
if (dateTime.hour > 11) then
dateTime.hour := dateTime.hour - 12;
SetOrigin(-cxSize, -cySize); {• make 0,0 in center */}
PenMode(srcXor);
{The text size is determined from the smallest side!}
if cxSize > cySize then
theTextSize := cySize div 5
else
theTextSize := cxSize div 5;
TextSize(theTextSize);
GetFontInfo(fInfo);
if (settings.display = 0) or (theTextSize < 6) then
begin
MoveTo(0, cySize - 2);
Line(0, 0); {• draw 4 ticks.}
MoveTo(cxSize - 2, 0);
Line(0, 0);
MoveTo(0, -cySize + 1);
Line(0, 0);
MoveTo(-cxSize + 1, 0);
Line(0, 0);
end
else if settings.display = 1 then
begin
PenMode(patXor);
if settings.black then
ForeColor(whiteColor);
MoveTo(0 - StringWidth('6') div 2, cySize - 2);
DrawString('6');
MoveTo(cxSize - 0 - StringWidth('3'), 0 + fInfo.ascent div 2);
DrawString('3');
MoveTo(0 - StringWidth('12') div 2, -cySize + 0 + fInfo.ascent);
DrawString('12');
MoveTo(-cxSize + 1, 0 + fInfo.ascent div 2);
DrawString('9');
ForeColor(blackColor);
end
else
begin
if settings.black then
ForeColor(whiteColor);
PenMode(patXor);
MoveTo(0 - StringWidth('VI') div 2, cySize - 2);
DrawString('VI');
MoveTo(cxSize - 0 - StringWidth('III'), 0 + fInfo.ascent div 2);
DrawString('III');
MoveTo(0 - StringWidth('XII') div 2, -cySize + 0 + fInfo.ascent);
DrawString('XII');
MoveTo(-cxSize + 1, 0 + fInfo.ascent div 2);
DrawString('IX');
ForeColor(blackColor);
end;
{Draw the rest of the marks}
MoveTo(Trunc((cxSize - 2) * 0.866), Trunc((cySize - 2) * 0.5));
Line(0, 0);
MoveTo(Trunc((cxSize - 2) * 0.5), Trunc((cySize - 2) * 0.866));
Line(0, 0);
MoveTo(-Trunc((cxSize - 2) * 0.866), Trunc((cySize - 2) * 0.5));
Line(0, 0);
MoveTo(-Trunc((cxSize - 2) * 0.5), Trunc((cySize - 2) * 0.866));
Line(0, 0);
MoveTo(Trunc((cxSize - 2) * 0.866), -Trunc((cySize - 2) * 0.5));
Line(0, 0);
MoveTo(Trunc((cxSize - 2) * 0.5), -Trunc((cySize - 2) * 0.866));
Line(0, 0);
MoveTo(-Trunc((cxSize - 2) * 0.866), -Trunc((cySize - 2) * 0.5));
Line(0, 0);
MoveTo(-Trunc((cxSize - 2) * 0.5), -Trunc((cySize - 2) * 0.866));
Line(0, 0);
{Draw EK}
MoveTo(0, cySize div 2); {5}
EK;
DrawHands(dateTime);
gPrevDateTime := dateTime;
end; {ShowClock}
procedure BackgroundTask;
var
dateTime: DateTimeRec; {• date gets read into here */}
begin
GetTime(dateTime);
if (dateTime.minute <> gPrevDateTime.minute) or (settings.seconds and (dateTime.second <> gPrevDateTime.second)) then
begin
SetPort(clockWindow);
PenMode(srcXor);
DrawHands(gPrevDateTime);
PenMode(srcXor);
DrawHands(dateTime);
gPrevDateTime := dateTime;
end;
end; {BackgroundTask}
procedure SetUpWindow;
var
wr: Rect;
begin
{$IFC UNDEFINED THINK_PASCAL}
dragRect := qd.screenBits.bounds;
{$ELSEC}
dragRect := screenBits.bounds;
{$ENDC}
{Color doesn't matter yet, but why not prepare for it?}
if gColorQDFlag then
clockWindow := GetNewCWindow(128, nil, WindowPtr(-1))
else
clockWindow := GetNewWindow(128, nil, WindowPtr(-1));
SetPort(clockWindow);
end; {SetUpWindow}
procedure SetUpMenus;
begin
appleMenu := NewMenu(appleID, stringof(char($14)));
InsertMenu(appleMenu, 0);
fileMenu := NewMenu(fileID, 'File');
InsertMenu(fileMenu, 0);
editMenu := NewMenu(editID, 'Edit');
InsertMenu(editMenu, 0);
optionsMenu := NewMenu(optionsID, 'Options');
InsertMenu(optionsMenu, 0);
AppendMenu(appleMenu, 'About NewWatch…');
{$IFC UNDEFINED THINK_PASCAL}
AppendResMenu(appleMenu, 'DRVR');
{$ELSEC}
AddResMenu(appleMenu, 'DRVR');
{$ENDC}
AppendMenu(fileMenu, 'Help/H;Standard size/N;(-;Quit/Q');
AppendMenu(editMenu, 'Undo/Z;(-;Cut/X;Copy/C;Paste/V;Clear');
AppendMenu(optionsMenu, 'White;Black;(-;Dots;Arabic;Roman;(-;Show seconds;Thick hands');
DrawMenuBar;
end; {SetUpMenus}
procedure AdjustMenus;
var
wp: WindowPeek;
kind: Integer;
DA: Boolean;
procedure Enable (menu: MenuHandle; item: Integer; ok: Boolean);
begin
if ok then
EnableItem(menu, item)
else
DisableItem(menu, item);
end; {Enable}
begin
wp := WindowPeek(FrontWindow);
if wp = nil then
kind := 0
else
kind := wp^.windowKind;
DA := kind < 0;
Enable(editMenu, 1, DA);
Enable(editMenu, 3, DA);
Enable(editMenu, 4, DA);
Enable(editMenu, 5, DA);
Enable(editMenu, 6, DA);
CheckItem(optionsMenu, 1, not settings.black);
CheckItem(optionsMenu, 2, settings.black);
CheckItem(optionsMenu, 4, settings.display = 0);
CheckItem(optionsMenu, 5, settings.display = 1);
CheckItem(optionsMenu, 6, settings.display = 2);
CheckItem(optionsMenu, 8, settings.seconds);
CheckItem(optionsMenu, 9, settings.fancy);
end; {AdjustMenus}
procedure HandleMenu (mSelect: LongInt);
var
menuID: Integer;
menuItem: Integer;
name: Str255;
savePort: GrafPtr;
theFrontWindow: WindowPeek;
begin
menuID := HiWrd(mSelect);
menuItem := LoWrd(mSelect);
case menuID of
appleID:
if menuItem = 1 then
begin
if Alert(128, nil) = 1 then {About…}
;
end
else
begin
GetPort(savePort);
{$IFC UNDEFINED THINK_PASCAL}
GetMenuItemText(appleMenu, menuItem, name);
{$ELSEC}
GetItem(appleMenu, menuItem, name);
{$ENDC}
if OpenDeskAcc(name) = 0 then
;
SetPort(savePort);
end;
fileID:
case menuItem of
helpItem:
begin
if Alert(129, nil) = 1 then {Show help text}
;
end;
defaultItem:
begin
SizeWindow(clockWindow, 32, 32, false);
SetPort(clockWindow);
InvalRect(clockWindow^.portRect);
{Move it to some safe place too}
MoveWindow(clockWindow, 40, 40, true);
end;
quitItem:
gDone := true;
end; {case}
editID:
if not SystemEdit(menuItem - 1) then
SysBeep(5);
optionsID:
begin
case menuItem of
1:
settings.black := false;
2:
settings.black := true;
8:
settings.seconds := not settings.seconds;
9:
settings.fancy := not settings.fancy;
otherwise
settings.display := menuItem - 4;
end; {case}
InvalRect(clockWindow^.portRect);
AdjustMenus;
end;
end;
end; {HandleMenu}
procedure InitMacintosh;
const
_WaitNextEvent = $A860;
_Unimplemented = $A89F;
_GetCIcon = $AA1E; {E.g. any Color QuickDraw routine}
k32bQD = $AB1D;
begin
{$IFC UNDEFINED THINK_PASCAL}
MaxApplZone;
InitGraf(@qd.thePort);
InitFonts;
FlushEvents(everyEvent, 0);
InitWindows;
InitMenus;
TEInit;
InitDialogs(nil);
{$ENDC}
InitCursor;
gHasWNE := NGetTrapAddress(_WaitNextEvent, ToolTrap) <> NGetTrapAddress(_Unimplemented, ToolTrap);
gColorQDFlag := NGetTrapAddress(_GetCIcon, ToolTrap) <> NGetTrapAddress(_Unimplemented, ToolTrap);
g32bQDFlag := NGetTrapAddress(k32bQD, ToolTrap) <> NGetTrapAddress(_Unimplemented, ToolTrap);
end;
procedure HandleMouseDown (var theEvent: EventRecord);
var
theWindow: WindowPtr;
windowCode: Integer;
growResult: Longint;
begin
windowCode := FindWindow(theEvent.where, theWindow);
case windowCode of
inSysWindow:
SystemClick(theEvent, theWindow);
inMenuBar:
begin
AdjustMenus;
HandleMenu(MenuSelect(theEvent.where));
end;
inDrag: {We should not have any, but just in case someone hacks it…}
if theWindow = clockWindow then
DragWindow(clockWindow, theEvent.where, dragRect);
inContent:
if theWindow = clockWindow then
begin
if theWindow <> FrontWindow then
SelectWindow(clockWindow)
else if BAnd(theEvent.modifiers, optionKey) <> 0 then {Option-klick = resize!}
begin
growResult := GrowWindow(clockWindow, theEvent.where, GetGrayRgn^^.rgnBBox);
if growResult <> 0 then
begin
SizeWindow(clockWindow, LoWrd(growResult), HiWrd(growResult), false);
SetPort(clockWindow);
InvalRect(clockWindow^.portRect);
end;
end
else
DragWindow(clockWindow, theEvent.where, dragRect);
end;
{ inGoAway: }
{ if (theWindow = clockWindow) then if TrackGoAway(clockWindow, theEvent.where) then}
{ gDone := true;}
end;
end;
procedure HandleEvent;
var
ok: Boolean;
theEvent: EventRecord;
begin
HiliteMenu(0);
if gHasWNE then
ok := WaitNextEvent(everyEvent, theEvent, 60, nil) {sleeptime of 1 second - we can't need more if we have a seconds hand!}
else
begin
SystemTask; {• Handle desk accessories.}
ok := GetNextEvent(everyEvent, theEvent);
end;
if ok then
case theEvent.what of
mouseDown:
HandleMouseDown(theEvent);
keyDown, autoKey:
if BAnd(theEvent.modifiers, cmdKey) <> 0 then
begin
AdjustMenus;
HandleMenu(MenuKey(char(BAnd(theEvent.message, charCodeMask))));
end;
updateEvt:
begin
{Because of the xor-based updates, I can't just update a part of the window, but must}
{invalidate all of it!}
SetPort(clockWindow);
InvalRect(clockWindow^.portRect);
{After that, a normal update!}
BeginUpdate(clockWindow);
ShowClock;
EndUpdate(clockWindow);
end;
activateEvt:
InvalRect(clockWindow^.portRect);
end
else
BackgroundTask;
end; {HandleEvent}
{ main program }
begin
InitMacintosh;
SetUpMenus;
SetUpWindow;
settings := SettingsType(GetWRefCon(clockWindow));
ShowClock;
while not gDone do
HandleEvent;
SetPort(clockWindow);
wt := WindowTHnd(GetResource('WIND', 128));
wt^^.boundsRect := clockWindow^.portRect;
LocalToGlobal(wt^^.boundsRect.topLeft);
LocalToGlobal(wt^^.boundsRect.botRight);
wt^^.refCon := Longint(settings);
ChangedResource(Handle(wt));
end.